package hikari.instruments.navmesh;

import com.gooddies.wiring.annotations.Wire;
import hikari.instruments.CameraObserveInstrument;
import hikari.managers.Manager3D;
import hikari.objects3d.NavMesh3dObject;
import hikari.utils.Utils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.swig.jirr.IMeshSceneNode;
import org.swig.jirr.ISceneCollisionManager;
import org.swig.jirr.ISceneManager;
import org.swig.jirr.ISceneNode;
import org.swig.jirr.ITriangleSelector;
import org.swig.jirr.S3DVertex;
import org.swig.jirr.SColor;
import org.swig.jirr.line3df;
import org.swig.jirr.triangle3df;
import org.swig.jirr.vector2df;
import org.swig.jirr.vector2di;
import org.swig.jirr.vector3df;

/**
 * @author Dmitry
 */
public abstract class NavmeshInstrument extends CameraObserveInstrument {

    private NavMesh3dObject mesh;
    private List<IMeshSceneNode> spheresVertex = new ArrayList<>();
    private HashMap<ISceneNode, S3DVertex> nodeToVertexMap = new HashMap<>();
    protected final float Y_OFFSET = 1f;
    @Wire
    private Manager3D manager3D;
    @Wire
    protected Utils utils;

    protected NavmeshInstrument() {
        
    }
    
    public void setObject(NavMesh3dObject obj){
        mesh = obj;
    }

    public List<IMeshSceneNode> getSpheresVertex() {
        return spheresVertex;
    }

    protected ISceneNode trySelect(int x, int y) {
        ISceneCollisionManager sc = manager3D.getSceneManager().getSceneCollisionManager();
        line3df ray = sc.getRayFromScreenCoordinates(new vector2di(x, y));
        vector3df pos = new vector3df();
        triangle3df triangle = new triangle3df();
        ISceneNode node = sc.getSceneNodeAndCollisionPointFromRay(ray, pos, triangle, 0, getMesh().getMeshSceneNode());
        return node;
    }

    protected int getIndex(ISceneNode node) {
        int index = 0;
        for (ISceneNode n : getSpheresVertex()) {
            if (n.equals(node)) {
                return index;
            }
            index++;
        }
        return -1;
    }

    protected IMeshSceneNode addVertex(vector3df pos) {
        vector3df newPos = getMesh().getMeshSceneNode().convertGlobalVectorToLocalSpace(pos);
        S3DVertex vertex = new S3DVertex(newPos, newPos, SColor.BLUE_L, new vector2df(0, 0));
        S3DVertex newV = getMesh().getMeshSceneNode().addVertex(vertex);
        getMesh().getMeshSceneNode().recalculate();
        return addSphereVertexAtPosition(newV);
    }

    public void addSphereVertex(IMeshSceneNode node) {
        spheresVertex.add(node);
    }

    protected vector3df calculatePositionOfPointer(int x, int y) {
        ISceneCollisionManager cm = manager3D.getSceneManager().getSceneCollisionManager();
        line3df line = cm.getRayFromScreenCoordinates(new vector2di(x, y));
        vector3df point = new vector3df();
        triangle3df triangle = new triangle3df();
        ISceneNode node = cm.getSceneNodeAndCollisionPointFromRay(line, point, triangle);
        if (node != null) {
            return new vector3df(point.getX(), point.getY() + Y_OFFSET, point.getZ());
        }

        float px;
        float py = 0;
        float pz;
        float x1 = line.getStart().getX();
        float x2 = line.getEnd().getX();
        float y1 = line.getStart().getY();
        float y2 = line.getEnd().getY();
        float z1 = line.getStart().getZ();
        float z2 = line.getEnd().getZ();
        if (y2 - y1 == 0) {
            return null;
        }

        float coeficient = (0 - y1) / (y2 - y1);
        px = coeficient * (x2 - x1) + x1;
        pz = coeficient * (z2 - z1) + z1;
        return new vector3df(px, py + Y_OFFSET, pz);

    }

    protected IMeshSceneNode createSphere(SColor color) {
        IMeshSceneNode node = manager3D.getSceneManager().addSphereSceneNode(0.5f);
        node.getMaterial(0).setDiffuseColor(color);
        node.getMaterial(0).setSpecularColor(color);
        node.getMaterial(0).setAmbientColor(color);
        manager3D.getSceneManager().getMeshManipulator().setVertexColors(node.getMesh(), color);
        return node;
    }

    public NavMesh3dObject getMesh() {
        return mesh;
    }

    protected IMeshSceneNode addSphereVertexAtPosition(S3DVertex vertex) {
        IMeshSceneNode vertexSphere = createSphere(SColor.BLUE);
        addSphereVertex(vertexSphere);
        vertexSphere.setPosition(vertex.getPos());
        vertexSphere.setParent(getMesh().getMeshSceneNode());
        nodeToVertexMap.put(vertexSphere, vertex);
        return vertexSphere;
    }

    protected S3DVertex getVertexByVertexSphere(ISceneNode node) {
        return nodeToVertexMap.get(node);
    }

    protected void addVertexSpheresArMeshVertexPositions() {
        for (S3DVertex vertex : getMesh().getMeshSceneNode().getVertices()) {
            addSphereVertexAtPosition(vertex);
        }
    }

    @Override
    public void instrumentActivate() {
        super.instrumentActivate();
        addVertexSpheresArMeshVertexPositions();
    }

    protected void resetInstrument() {
        for (ISceneNode spheres : spheresVertex) {
            spheres.remove();
        }
        spheresVertex.clear();
        nodeToVertexMap.clear();
    }

    @Override
    public void instrumentDeactivate() {
        super.instrumentDeactivate();
        //remove all vertex spheres
        resetInstrument();
    }

    protected void addMeshSelectorToAllSphereVertexes() {
        for (IMeshSceneNode node : (List<IMeshSceneNode>) getSpheresVertex()) {
            addMeshSelectorToNode(node);
        }
    }

    protected void addMeshSelectorToNode(ISceneNode node) {
        ISceneManager sm = manager3D.getSceneManager();
        ITriangleSelector selector = sm.createTriangleSelectorFromBoundingBox(node);
        node.setTriangleSelector(selector);
    }
}
